﻿//#define AST

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

using PSLib.Parsing.Lua;
using Antlr.Runtime.Tree;
using Antlr.Runtime;

namespace ANTLRTest
{
    enum ParseType
    {
        File,
        Batch
    }
    
    class Program
    {
        public static readonly string DumpOutputDirectory = @"d:\Temp\Logs\";
        public static readonly string BatchStartDirectory = @"x:\Documents\games\World of Warcraft\Interface\AddOns\";
        
        static void FileRun(string filePath,string outputDirectory, bool generateErrorsDump, bool objectModelDump, bool generateTokenDump)
        {
            if(!File.Exists(filePath)) 
            {
                Console.WriteLine(filePath + "file does not exists.");
                return;
            }
            string fileName = Path.GetFileNameWithoutExtension(filePath);


            //Check dump errors option
            if (generateErrorsDump)
            {
                TextWriter errStream = new StreamWriter(string.Format("{0}\\{1}.err", outputDirectory, fileName));
                Console.SetError(errStream);
            }

            DateTime startdate = DateTime.Now;
            //Create stream from file
            Antlr.Runtime.ICharStream st = new Antlr.Runtime.ANTLRFileStream(filePath);

            //Create lua lexer
            Lua2Lexer lexer = new Lua2Lexer(st);
            //Antlr.Runtime.TokenRewriteStream tokenStream = new Antlr.Runtime.TokenRewriteStream() { TokenSource = lexer };
            Antlr.Runtime.CommonTokenStream tokenStream = new Antlr.Runtime.CommonTokenStream() { TokenSource = lexer };
            
            //Create lua parser
            Lua2Parser parser = new Lua2Parser(tokenStream);

            //Parse source
            parser.TreeAdaptor = new LuaTreeAdaptor();
            Lua2Parser.program_return result = parser.program();
            LuaTreeNode ssss = result.Tree as LuaTreeNode;

            DateTime enddate = DateTime.Now;

            Console.WriteLine("Compile time: {0}", enddate - startdate);
            //Close error log
            if (generateErrorsDump) Console.Error.Close();

            //Check dump parsing tree dump option
            if (objectModelDump)
            {
                string parsingTreeFileName = string.Format("{0}\\{1}.treeDump.xml", outputDirectory, fileName);
                string parsingTreeResult = Program.DumpTree(ssss);
                File.WriteAllText(parsingTreeFileName, parsingTreeResult);
            }

            //Check dump lexem tree dump option
            if (generateTokenDump)
            {
                string tokensFileName = string.Format("{0}\\{1}.tokenDump.xml", outputDirectory, fileName);
                string tokensResult = Program.DumpTokenStream(tokenStream);
                File.WriteAllText(tokensFileName, tokensResult);
            }

        }

        static void BatchRun(string batchStartDirectory, string outputDirectory, bool generateErrorsDump, bool objectModelDump, bool generateTokenDump)
        {
            string[] files = System.IO.Directory.GetFiles(batchStartDirectory, "*.lua", System.IO.SearchOption.AllDirectories);
            foreach (var item in files)
                FileRun(item, outputDirectory, generateErrorsDump, objectModelDump, generateTokenDump);
        }

        static string DumpTree(Antlr.Runtime.Tree.CommonTree tree)
        {
            XmlDocument doc = new XmlDocument();
            XmlNode root = doc.CreateElement("tree");
            DumpTree_r(root, tree);
            doc.AppendChild(root);
            return doc.InnerXml;
        }

        static void DumpTree_r(XmlNode root, CommonTree tree)
        {
            XmlNode child = root.OwnerDocument.CreateElement("tree");
            if (tree.Token != null)
            {
                child.AddAttribute("name", tree.Token.Text);
                child.AddAttribute("type", Lua2Parser.tokenNames[tree.Token.Type]);
            }

            if (tree.Children != null)
            {
                foreach (var item in tree.Children)
                {
                    CommonTree childTree = item as CommonTree;
                    DumpTree_r(child, childTree);
                }
            }
            root.AppendChild(child);
        }

        static string DumpTokenStream(Antlr.Runtime.CommonTokenStream stream)
        {
            XmlDocument doc = new XmlDocument();
            XmlNode root = doc.CreateElement("tokens");

            foreach (Antlr.Runtime.IToken token in stream.GetTokens())
            {
                XmlNode node = root.OwnerDocument.CreateElement("t");
                node.AddAttribute("type", Lua2Parser.tokenNames[token.Type]);
                node.AddAttribute("value", token.Text);
                node.AddAttribute("channel", token.Channel.ToString());
                XmlNode posNode = root.OwnerDocument.CreateElement("pos");
                posNode.AddAttribute("line", token.Line.ToString());
                posNode.AddAttribute("start", token.CharPositionInLine.ToString());
                posNode.AddAttribute("stop", (token.CharPositionInLine + token.Text.Length).ToString());
                node.AppendChild(posNode);
                root.AppendChild(node);
            }
            doc.AppendChild(root);
            return doc.InnerXml;
        }
        
        static void Main(string[] args)
        {
            ParseType type = ParseType.File;

            switch (type)
            {
                case ParseType.File:
                    Program.FileRun("test.lua", Program.DumpOutputDirectory, false, true, true);
                    break;
                case ParseType.Batch:
                    Program.BatchRun(Program.BatchStartDirectory, Program.DumpOutputDirectory, true, true, true);
                    break;
                default:
                    Console.WriteLine("Unknown parse type.");
                    break;
            }

            Console.WriteLine("Completed");
            Console.ReadKey();
        }
    }
}
